﻿using System;
using System.Data;
using System.Text;
using System.Web;
using Me.Amon.C;
using Me.Amon.Da.Db;
using Me.Amon.Da.Db.OMS;
using Me.Amon.Da.Db.POS;
using Me.Amon.M;
using Me.Amon.POS.C;
using Me.Amon.POS.M;
using Me.Amon.Util;
using Newtonsoft.Json;

namespace Me.Amon.POS
{
    /// <summary>
    /// So 的摘要说明
    /// </summary>
    public class So : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            context.Response.ContentEncoding = Encoding.UTF8;

            // 公司
            var corp = context.Request[PPos.PARAM_KEY_CORP];
            if (string.IsNullOrEmpty(corp))
            {
                var obj = new MSoHeader();
                obj.error_code = PPos.ERROR_CODE_CORP_EMPTY;
                context.Response.Write(JsonConvert.SerializeObject(obj, Formatting.None));
                context.Response.End();
                return;
            }

            // 操作
            var opt = context.Request[CObj.PARAM_KEY_OPT];
            if (string.IsNullOrEmpty(opt))
            {
                var obj = new MSoHeader();
                obj.error_code = PObj.ERROR_CODE_OPT_EMPTY;
                context.Response.Write(JsonConvert.SerializeObject(obj, Formatting.None));
                context.Response.End();
                return;
            }

            switch (opt)
            {
                case CSoHeader.PARAM_VALUE_OPT_UPDATE_SO_DETAIL:
                    UpdateSoDetail(context);
                    break;
                case CSoHeader.PARAM_VALUE_OPT_CREATE_SO_HEADER:
                    CreateSoHeader(context);
                    break;
                case CSoHeader.PARAM_VALUE_OPT_UPDATE_SO_HEADER:
                    UpdateSoHeader(context);
                    break;
                case CSoHeader.PARAM_VALUE_OPT_SELECT_SO_HEADER:
                    SelectSoHeader(context);
                    break;
                default:
                    var obj = new MObj();
                    obj.error_code = PObj.ERROR_CODE_OPT_ERROR;
                    context.Response.Write(JsonConvert.SerializeObject(obj, Formatting.None));
                    break;
            }
            context.Response.End();
        }

        private void SelectSoHeader(HttpContext context)
        {
            var corp = context.Request[PPos.PARAM_KEY_CORP];
            if (string.IsNullOrWhiteSpace(corp))
            {
                var obj = new MObj();
                obj.error_code = PPos.ERROR_CODE_CORP_EMPTY;
                context.Response.Write(JsonConvert.SerializeObject(obj, Formatting.None));
                context.Response.End();
                return;
            }

            var user = context.Request[PPos.PARAM_KEY_USER];
            if (string.IsNullOrWhiteSpace(user))
            {
                var obj = new MObj();
                obj.error_code = PPos.ERROR_CODE_CORP_EMPTY;
                context.Response.Write(JsonConvert.SerializeObject(obj, Formatting.None));
                context.Response.End();
                return;
            }

            var dba = new RDBEngine();
            dba.AddTable(DSoHeader.TABLE);
            dba.AddWhere(DSoHeader.CORP_ID, corp);
            dba.AddWhere(DSoHeader.CREATE_USER, user);
            dba.AddWhere(DSoHeader.STATUS, CSoHeader.ORDER_STATUS_DELAYED.ToString(), false, false);
            dba.AddSort(DSoHeader.CREATE_TIME, false);

            var dt = dba.ExecuteSelect();
            var cnt = dt.Rows.Count;
            var sos = new MSoHeader[cnt];
            for (int i = 0; i < cnt; i += 1)
            {
                sos[i] = ReadSoHeader(dt.Rows[i], dba);
            }

            context.Response.Write(JsonConvert.SerializeObject(sos));
        }

        private MSoHeader ReadSoHeader(DataRow row, RDBEngine dba)
        {
            var so = new MSoHeader();
            so.id = row[DSoHeader.ID] as string;
            so.code = row[DSoHeader.CODE] as string;
            so.channel = row[DSoHeader.CHANNEL] as string;
            so.terminal = row[DSoHeader.TERMINAL] as string;
            so.status = (int)row[DSoHeader.STATUS];
            so.vip_id = row[DSoHeader.VIP_ID] as string;
            so.item_qty = (int)row[DSoHeader.ITEM_QTY];
            so.unit_qty = (int)row[DSoHeader.UNIT_QTY];
            so.order_amount = (int)row[DSoHeader.ORDER_AMOUNT];
            so.round_amount = (int)row[DSoHeader.ROUND_AMOUNT];
            so.prepay_amount = (int)row[DSoHeader.PREPAY_AMOUNT];
            so.change_amount = (int)row[DSoHeader.CHANGE_AMOUNT];
            so.update_time = (DateTime)row[DSoHeader.UPDATE_TIME];
            so.update_user = row[DSoHeader.UPDATE_USER] as string;
            so.create_time = (DateTime)row[DSoHeader.CREATE_TIME];
            so.create_user = row[DSoHeader.CREATE_USER] as string;
            so.corp_id = row[DSoHeader.CORP_ID] as string;

            SelectSoDetail(so, dba);

            return so;
        }

        private void CreateSoHeader(HttpContext context)
        {
            // 数据
            var dat = context.Request[PPos.PARAM_KEY_DATA];
            if (string.IsNullOrWhiteSpace(dat))
            {
                var obj = new MObj();
                obj.error_code = PPos.ERROR_CODE_DAT_EMPTY;
                context.Response.Write(JsonConvert.SerializeObject(obj, Formatting.None));
                context.Response.End();
                return;
            }

            MSoHeader soHeader = null;
            try
            {
                soHeader = JsonConvert.DeserializeObject<MSoHeader>(dat);
            }
            catch (Exception exp)
            {
                var obj = new MObj();
                obj.error_code = PObj.ERROR_CODE_CUSTOM;
                obj.error_message = exp.Message;
                context.Response.Write(JsonConvert.SerializeObject(obj, Formatting.None));
                context.Response.End();
                return;
            }

            var now = DateTime.Now;
            var pre = "SO" + now.ToString("yyyyMMdd");

            var dba = new RDBEngine();
            dba.AddTable(DSoHeader.TABLE);
            dba.AddColumn(string.Format("MAX({0})", DSoHeader.CODE), DSoHeader.CODE);
            dba.AddWhere(DSoHeader.CODE, "LIKE", pre + '%', true);

            var dt = dba.ExecuteSelect();
            if (dt.Rows.Count < 1)
            {
                soHeader.code = pre + "000001";
            }
            else
            {
                var key = dt.Rows[0][0] as string;
                if (!string.IsNullOrWhiteSpace(key) && key.Length > 6)
                {
                    key = key.Substring(key.Length - 6, 6);
                }
                if (CharUtil.IsValidateLong(key))
                {
                    soHeader.code = pre + (int.Parse(key) + 1).ToString("000000");
                }
                else
                {
                    soHeader.code = pre + "000001";
                }
            }

            soHeader.id = HashUtil.UtcTimeInHex();

            dba.Reset();
            dba.AddTable(DSoHeader.TABLE);
            dba.AddParam(DSoHeader.ID, soHeader.id);
            dba.AddParam(DSoHeader.CORP_ID, soHeader.corp_id);
            dba.AddParam(DSoHeader.CODE, soHeader.code);
            dba.AddParam(DSoHeader.CHANNEL, CSoHeader.CHANNEL_NAME);
            dba.AddParam(DSoHeader.TERMINAL, soHeader.terminal);
            dba.AddParam(DSoHeader.VIP_ID, soHeader.vip_id);
            dba.AddParam(DSoHeader.ITEM_QTY, 0);
            dba.AddParam(DSoHeader.UNIT_QTY, 0);
            dba.AddParam(DSoHeader.ORDER_AMOUNT, 0);
            dba.AddParam(DSoHeader.ROUND_AMOUNT, 0);
            dba.AddParam(DSoHeader.STATUS, CSoHeader.STATUE_ENABLED);
            dba.AddParam(DSoHeader.UPDATE_TIME, DSoHeader.NOW, false);
            dba.AddParam(DSoHeader.UPDATE_USER, soHeader.update_user);
            dba.AddParam(DSoHeader.CREATE_TIME, DSoHeader.NOW, false);
            dba.AddParam(DSoHeader.CREATE_USER, soHeader.create_user);
            dba.ExecuteInsert();

            context.Response.Write(JsonConvert.SerializeObject(soHeader));
            context.Response.End();
        }

        /// <summary>
        /// 更新订单状态
        /// </summary>
        /// <param name="context"></param>
        private void UpdateSoHeader(HttpContext context)
        {
            // 数据
            var dat = context.Request[PPos.PARAM_KEY_DATA];
            if (string.IsNullOrWhiteSpace(dat))
            {
                var obj = new MObj();
                obj.error_code = PPos.ERROR_CODE_DAT_EMPTY;
                context.Response.Write(JsonConvert.SerializeObject(obj, Formatting.None));
                context.Response.End();
                return;
            }

            MSoHeader soHeader;
            try
            {
                soHeader = JsonConvert.DeserializeObject<MSoHeader>(dat);
            }
            catch (Exception exp)
            {
                var obj = new MObj();
                obj.error_code = PObj.ERROR_CODE_CUSTOM;
                obj.error_message = exp.Message;
                context.Response.Write(JsonConvert.SerializeObject(obj, Formatting.None));
                context.Response.End();
                return;
            }

            if (!CharUtil.IsValidateHash(soHeader.id))
            {
                return;
            }

            // 扣除库存
            var dba = new RDBEngine();
            dba.AddTable(DSoDetail.TABLE);
            dba.AddColumn(DSoDetail.SPU_ID);
            dba.AddColumn(DSoDetail.SPU_QTY);
            dba.AddWhere(DSoDetail.SO_ID, soHeader.id);
            var dt = dba.ExecuteSelect();
            string spu;
            int qty;
            long key = HashUtil.UtcTime();
            foreach (DataRow row in dt.Rows)
            {
                spu = row[DSoDetail.SPU_ID] as string;
                qty = (int)row[DSoDetail.SPU_QTY];

                dba.Reset();
                dba.AddTable(DSpuInv.TABLE);
                dba.AddParam(DSpuInv.ID, key.ToString("x16"));
                dba.AddParam(DSpuInv.SPU_ID, spu);
                dba.AddParam(DSpuInv.INV, -qty);
                dba.AddParam(DSpuInv.SOURCE, CSpuInv.SOURCE_ORDER.ToString());
                dba.AddParam(DSpuInv.ORDER_ID, soHeader.id);
                dba.AddParam(DSpuInv.ORDER_CODE, soHeader.code);
                dba.AddParam(DSpuInv.CREATE_TIME, DSpuInv.NOW, false);
                dba.AddParam(DSpuInv.CREATE_USER, soHeader.create_user);
                dba.AddInsertBatch();

                dba.Reset();
                dba.AddTable(DSpu.TABLE);
                dba.AddParam(DSpu.USABLE_INV, DSpu.USABLE_INV + "-" + qty, false);
                dba.AddWhere(DSpu.ID, spu);
                dba.AddUpdateBatch();

                key += 1;
            }

            // 更新订单信息
            dba.Reset();
            dba.AddTable(DSoHeader.TABLE);
            dba.AddParam(DSoHeader.CORP_ID, soHeader.corp_id);
            dba.AddParam(DSoHeader.VIP_ID, soHeader.vip_id);
            dba.AddParam(DSoHeader.ITEM_QTY, soHeader.item_qty);
            dba.AddParam(DSoHeader.UNIT_QTY, soHeader.unit_qty);
            dba.AddParam(DSoHeader.ORDER_AMOUNT, soHeader.order_amount);
            dba.AddParam(DSoHeader.ROUND_AMOUNT, soHeader.round_amount);
            dba.AddParam(DSoHeader.PREPAY_AMOUNT, soHeader.prepay_amount);
            dba.AddParam(DSoHeader.CHANGE_AMOUNT, soHeader.change_amount);
            dba.AddParam(DSoHeader.STATUS, soHeader.status);
            dba.AddWhere(DSoHeader.ID, soHeader.id);
            dba.AddUpdateBatch();

            // 计算积分
            if (soHeader.status == CSoHeader.ORDER_STATUS_FINISHED && CharUtil.IsValidateHash(soHeader.vip_id))
            {
                dba.Reset();
                dba.AddTable(DVip.TABLE);
                dba.AddParam(DVip.POINT, DVip.POINT + "+" + (soHeader.round_amount / 100), false);
                dba.AddWhere(DVip.ID, soHeader.vip_id);
                dba.AddUpdateBatch();
            }

            dba.ExecuteBatch();
        }

        private void SelectSoDetail(MSoHeader header, RDBEngine dba)
        {
            dba.Reset();
            dba.AddTable(DSoDetail.TABLE);
            dba.AddWhere(DSoDetail.SO_ID, header.id);
            var dt = dba.ExecuteSelect();
            int cnt = dt.Rows.Count;
            header.details = new MSoDetail[cnt];
            for (int i = 0; i < cnt; i += 1)
            {
                header.details[i] = ReadSoDetail(dt.Rows[i]);
            }
        }

        private MSoDetail ReadSoDetail(DataRow row)
        {
            var soDetail = new MSoDetail();
            soDetail.id = row[DSoDetail.ID] as string;
            soDetail.so_id = row[DSoDetail.SO_ID] as string;
            soDetail.spu_id = row[DSoDetail.SPU_QTY] as string;
            soDetail.spu_qty = (int)row[DSoDetail.SPU_QTY];
            soDetail.spu_price = (int)row[DSoDetail.SPU_PRICE];
            soDetail.vip_price = (int)row[DSoDetail.VIP_PRICE];
            soDetail.pro_price = (int)row[DSoDetail.PRO_PRICE];
            soDetail.pro_name = row[DSoDetail.PRO_TYPE] as string;
            soDetail.guider = row[DSoDetail.GUIDER] as string;
            soDetail.subtotal = (int)row[DSoDetail.SUBTOTAL];
            return soDetail;
        }

        private void UpdateSoDetail(HttpContext context)
        {
            var data = context.Request[PPos.PARAM_KEY_DATA];
            if (string.IsNullOrWhiteSpace(data))
            {
                var obj = new MObj();
                obj.error_code = PPos.ERROR_CODE_DAT_EMPTY;
                context.Response.Write(JsonConvert.SerializeObject(obj, Formatting.None));
                context.Response.End();
                return;
            }

            MSoDetail soDetail = null;
            try
            {
                soDetail = JsonConvert.DeserializeObject<MSoDetail>(data);
            }
            catch (Exception exp)
            {
                var obj = new MObj();
                obj.error_code = PObj.ERROR_CODE_CUSTOM;
                obj.error_message = exp.Message;
                context.Response.Write(JsonConvert.SerializeObject(obj, Formatting.None));
                context.Response.End();
                return;
            }

            var dba = new RDBEngine();
            dba.AddTable(DSoDetail.TABLE);
            dba.AddParam(DSoDetail.SO_ID, soDetail.so_id);
            dba.AddParam(DSoDetail.SPU_ID, soDetail.spu_id);
            dba.AddParam(DSoDetail.SPU_QTY, soDetail.spu_qty);
            dba.AddParam(DSoDetail.SPU_PRICE, soDetail.spu_price);
            dba.AddParam(DSoDetail.VIP_PRICE, soDetail.vip_price);
            dba.AddParam(DSoDetail.PRO_PRICE, soDetail.pro_price);
            dba.AddParam(DSoDetail.PRO_TYPE, soDetail.pro_name);
            dba.AddParam(DSoDetail.GUIDER, soDetail.guider);
            dba.AddParam(DSoDetail.SUBTOTAL, soDetail.subtotal);
            dba.AddParam(DSoDetail.UPDATE_TIME, DSoDetail.NOW, false);
            dba.AddParam(DSoDetail.UPDATE_USER, soDetail.update_user);

            if (CharUtil.IsValidateHash(soDetail.id))
            {
                dba.AddWhere(DSoDetail.ID, soDetail.id);
                dba.ExecuteUpdate();
            }
            else
            {
                soDetail.id = HashUtil.UtcTimeInHex();
                dba.AddParam(DSoDetail.ID, soDetail.id);
                dba.ExecuteInsert();
            }

            context.Response.Write(JsonConvert.SerializeObject(soDetail));
            context.Response.End();
        }

        private void DeleteSoDetail(HttpContext context)
        {
            var data = context.Request[PPos.PARAM_KEY_DATA];
            if (string.IsNullOrWhiteSpace(data))
            {
                var obj = new MObj();
                obj.error_code = PPos.ERROR_CODE_DAT_EMPTY;
                context.Response.Write(JsonConvert.SerializeObject(obj, Formatting.None));
                context.Response.End();
                return;
            }

            MSoDetail soDetail = null;
            try
            {
                soDetail = JsonConvert.DeserializeObject<MSoDetail>(data);
            }
            catch (Exception exp)
            {
                var obj = new MObj();
                obj.error_code = PObj.ERROR_CODE_CUSTOM;
                obj.error_message = exp.Message;
                context.Response.Write(JsonConvert.SerializeObject(obj, Formatting.None));
                context.Response.End();
                return;
            }

            var dba = new RDBEngine();
            dba.AddTable(DSoDetail.TABLE);
            dba.AddWhere(DSoDetail.ID, soDetail.id);
            dba.ExecuteDelete();
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}